package com.yong.opengl.ui.draw_triangle;

import android.content.Context;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.util.Log;

import com.yong.opengl.R;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import java.util.ArrayList;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

/**
 * @version 1.0
 * @Description: 绘制一个三角形
 * @Author: yong
 * @time 2021/3/31 0031 10:21
 */
public class DrawTriangleRender implements GLSurfaceView.Renderer {
    /**
     * 一个Float占用4Byte
     */
    private static final int BYTES_PER_FLOAT = 4;
    /**
     * 三个顶点
     */
    private static final int POSITION_COMPONENT_COUNT = 3;
    /**
     * 顶点位置缓存(采用索引的方式)
     */
    private final FloatBuffer vertexBuffer;
    /**
     * 顶点颜色缓存
     */
    private final FloatBuffer colorBuffer;
    /**
     * 顶点位置索引
     */
    private final ShortBuffer indicesBuffer;
    /**
     * 默认是一个三角形
     */
    private short[] indices = {0, 1, 2};
    /**
     * 渲染程序
     */
    private int mProgram;

    /**
     * 相机矩阵
     */
    private final float[] mViewMatrix = new float[16];
    /**
     * 投影矩阵
     */
    private final float[] mProjectMatrix = new float[16];
    /**
     * 最终变换矩阵
     */
    private final float[] mMVPMatrix = new float[16];

    //返回属性变量的位置
    /**
     * 变换矩阵
     */
    private int uMatrixLocation;
    /**
     * 位置
     */
    private int aPositionLocation;
    /**
     * 颜色
     */
    private int aColorLocation;


    private Context context;

    /**
     * 三个顶点的位置参数 (默认逆时针旋转)
     * 分别对应x,y,z
     * 坐标原点是整个画面的中心点
     */
    private float[] triangleCoords = {
            //top
            0.5f, 0.5f, 0.0f,
            //bottom left
            -0.5f, -0.5f, 0.0f,
            //bottom right
            0.5f, -0.5f, 0.0f
    };

    /**
     * 三个顶点的颜色参数(对应r,g,b,a)
     */
    private float[] color = {
            // top
            1.0f, 0.0f, 0.0f, 1.0f,
            // bottom left
            0.0f, 1.0f, 0.0f, 1.0f,
            // bottom right
            0.0f, 0.0f, 1.0f, 1.0f
    };

    public DrawTriangleRender(Context context) {
        //openGL的夫复杂图像都是多个三角形状共同组成的
        createPositions(1, 600);

        //顶点位置相关
        //分配本地内存空间,每个浮点型占4字节空间；将坐标数据转换为FloatBuffer，用以传入给OpenGL ES程序
        vertexBuffer = ByteBuffer.allocateDirect(triangleCoords.length * BYTES_PER_FLOAT)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();
        vertexBuffer.put(triangleCoords);
        vertexBuffer.position(0);

        //顶点颜色相关
        colorBuffer = ByteBuffer.allocateDirect(color.length * BYTES_PER_FLOAT)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();
        colorBuffer.put(color);
        colorBuffer.position(0);

        //索引
        indicesBuffer = ByteBuffer.allocateDirect(indices.length * BYTES_PER_FLOAT)
                .order(ByteOrder.nativeOrder())
                .asShortBuffer();
        indicesBuffer.put(indices);
        indicesBuffer.position(0);

        this.context = context;
    }

    private void createPositions(int radius, int n) {
        ArrayList<Float> data = new ArrayList<>();
        //设置圆心坐标
        data.add(0.0f);
        data.add(0.0f);
        data.add(0.0f);
        float angDegSpan = 360f / n;
        for (float i = 0; i < 360 + angDegSpan; i += angDegSpan) {
            data.add((float) (radius * Math.sin(i * Math.PI / 180f)));
            data.add((float) (radius * Math.cos(i * Math.PI / 180f)));
            data.add(0.0f);
        }
        float[] f = new float[data.size()];
        for (int i = 0; i < f.length; i++) {
            f[i] = data.get(i);
        }

        triangleCoords = f;

        //处理各个顶点的颜色
        color = new float[f.length * 4 / 3];
        ArrayList<Float> totalC = new ArrayList<>();
        for (int i = 0; i < color.length; i++) {
            totalC.add((float) Math.random());
        }

        for (int i = 0; i < totalC.size(); i++) {
            color[i] = totalC.get(i);
        }

        indices = new short[n*3];
        short x = 0;
        short y = 1;
        short z = 2;
        //处理各个索引
        for (int i = 0; i < indices.length/3; i++) {
            indices[i*3] = x;
            indices[i*3 + 1] = (short) (y + i);
            indices[i * 3 + 2] = (short) (z + i);
        }
    }


    @Override
    public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
        //将背景设置为白色
        GLES30.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);

        //编译顶点着色程序
        String vertexShaderStr = ResReadUtils.readResource(R.raw.vertex_simple_shade, context);
        int vertexShaderId = ShaderUtils.compileVertexShader(vertexShaderStr);
        //编译片段着色程序
        String fragmentShaderStr = ResReadUtils.readResource(R.raw.fragment_simple_shade, context);
        int fragmentShaderId = ShaderUtils.compileFragmentShader(fragmentShaderStr);
        //连接程序
        mProgram = ShaderUtils.linkProgram(vertexShaderId, fragmentShaderId);
        //在OpenGLES环境中使用程序
        GLES30.glUseProgram(mProgram);

        //变换矩阵
        uMatrixLocation = GLES30.glGetUniformLocation(mProgram, "u_Matrix");
        //位置
        aPositionLocation = GLES30.glGetAttribLocation(mProgram, "vPosition");
        //颜色
        aColorLocation = GLES30.glGetAttribLocation(mProgram, "aColor");
    }

    @Override
    public void onSurfaceChanged(GL10 gl10, int width, int height) {
        GLES30.glViewport(0, 0, width, height);

        //计算宽高比
        float ratio = (float) width / height;
        //设置透视投影(near<=10，far>near)
        Matrix.frustumM(mProjectMatrix, 0, -ratio, ratio, -1, 1, 3, 7.0f);
        //设置相机位置
        //float eyeX, //摄像机位置x
        //float eyeY, //摄像机位置y
        //float eyeZ, //摄像机位置z
        //float centerX, //摄像机目标点x
        //float centerY, //摄像机目标点y
        //float centerZ, //摄像机目标点z
        //float upX, //摄像机UP向量X分量
        //float upY, //摄像机UP向量Y分量
        //float upZ //摄像机UP向量Z分量
        Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 7.0f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
        //计算变换矩阵
        Matrix.multiplyMM(mMVPMatrix, 0, mProjectMatrix, 0, mViewMatrix, 0);

    }

    @Override
    public void onDrawFrame(GL10 gl10) {
        //把颜色缓冲区设定为我们预设的颜色
        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);

        //将变换矩阵传入顶点渲染器
        GLES30.glUniformMatrix4fv(uMatrixLocation, 1, false, mMVPMatrix, 0);
        //准备坐标数据
        GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT, false, 0, vertexBuffer);
        //启用顶点位置句柄
        GLES30.glEnableVertexAttribArray(aPositionLocation);

        //准备颜色数据
        GLES30.glVertexAttribPointer(1, 4, GLES30.GL_FLOAT, false, 0, colorBuffer);
        //启用顶点颜色句柄
        GLES30.glEnableVertexAttribArray(1);

        //绘制三个点
        //GLES30.glDrawArrays(GLES30.GL_POINTS, 0, POSITION_COMPONENT_COUNT);

        //绘制三条线
        //设置线宽
        //GLES30.glLineWidth(3);
        //GLES30.glDrawArrays(GLES30.GL_LINE_LOOP, 0, POSITION_COMPONENT_COUNT);

        //绘制三角形
        // GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, POSITION_COMPONENT_COUNT);

        //采用索引的方式绘制图形
        GLES30.glDrawElements(GLES30.GL_TRIANGLES, indices.length, GLES30.GL_UNSIGNED_SHORT, indicesBuffer);

        //禁止顶点数组的句柄
        GLES30.glDisableVertexAttribArray(aColorLocation);
        GLES30.glDisableVertexAttribArray(aPositionLocation);
    }
}
